package com.baofu.paycore.service;

import com.baofu.paycore.biz.model.BackPayBO;
import com.baofu.paycore.biz.paycore.handler.impl.UnfreezeWithdrawHandler;
import com.baofu.paycore.biz.paycore.handler.impl.WithdrawHandler;
import com.baofu.paycore.common.utils.ExceptionUtil;
import com.baofu.paycore.manager.model.withdraw.WithdrawBO;
import com.baofu.paycore.manager.storer.WithdrawOrderRepository;
import com.baofu.paycore.service.converter.BO2DTOConverter;
import com.baofu.paycore.service.facade.WithdrawServiceFacade;
import com.baofu.paycore.service.facade.enums.PayStatusEnums;
import com.baofu.paycore.service.facade.model.withdraw.UnfreezeWithdrawDTO;
import com.baofu.paycore.service.facade.model.withdraw.WithdrawDTO;
import com.baofu.paycore.service.facade.model.withdraw.WithdrawResDTO;
import com.baofu.paycore.service.factory.impl.UnfreezeWithdrawFactoryImpl;
import com.baofu.paycore.service.factory.impl.WithdrawFactoryImpl;
import com.baofu.paycore.service.validate.impl.withdraw.UnfreezeWithdrawValidate;
import com.baofu.paycore.service.validate.impl.withdraw.WithdrawValidate;
import com.system.commons.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.slf4j.helpers.SystemMarker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 *  提现接口
 *
 * <p>
 *  1.提现
 * </p>
 * User: xin deng  Date: 16/6/3 ProjectName: paycore Version: 1.0
 */
@Slf4j
@Service
public class WithdrawService implements WithdrawServiceFacade {

    /**
     * 提现参数校验
     */
    @Autowired
    private WithdrawValidate withdrawValidate;

    /**
     * 解冻提现参数校验
     */
    @Autowired
    private UnfreezeWithdrawValidate unfreezeWithdrawValidate;

    /**
     * 提现单处理器
     */
    @Autowired
    private WithdrawFactoryImpl withdrawFactory;


    /**
     * 提现单持久化服务
     */
    @Autowired
    private WithdrawOrderRepository withdrawOrderRepository;

    /**
     * 提现流程处理
     */
    @Autowired
    private WithdrawHandler withdrawHandler;

    /**
     * 解冻体现参数组装工具
     */
    @Autowired
    private UnfreezeWithdrawFactoryImpl unfreezeWithdrawFactory;

    /**
     * 解冻提现流程处理
     */
    @Autowired
    private UnfreezeWithdrawHandler unfreezeWithdrawHandler;


    /**
     * 提现
     *
     * @param withdrawDTO   提现请求参数
     * @param traceLogId    日志ID
     * @return              提现结果
     * response.isSuccess()标示方法的远程调用状态，方法实际执行结果从result 取值
     */
    @Override
    public Result<WithdrawResDTO> withdraw(WithdrawDTO withdrawDTO, String traceLogId) {
        long start = System.currentTimeMillis();
        Result<WithdrawResDTO> result = null;
        boolean flag = false;
        try{
            MDC.put(SystemMarker.TRACE_LOG_ID, traceLogId);

            log.info("提现请求参数:withdrawDTO {}", withdrawDTO);
            flag = withdrawValidate.lock(withdrawDTO);

            //1.请求参数校验
            withdrawValidate.paramsValidate(withdrawDTO);
            result = withdrawValidate.validateUniqueOrder(withdrawDTO, withdrawOrderRepository, WithdrawResDTO.class);
            if (result != null) {
                this.existOrderProcess(result);
                return result;
            }
            //2、请求对象转换
            WithdrawBO withdrawBO = withdrawFactory.build(withdrawDTO);
            withdrawBO.setTradeLogId(traceLogId);

            //3、支付相关信息落地
            withdrawOrderRepository.addOrder(withdrawBO);

            //4.业务流程处理
            BackPayBO backPayBO = withdrawHandler.process(withdrawBO);

            //5、接口返回对象生成
            WithdrawResDTO withdrawResDTO = BO2DTOConverter.getWithdrawResDTO(backPayBO);
            result = new Result<>(withdrawResDTO);

        }catch (Exception e){
            log.error("提现异常:{}", e);
            result = ExceptionUtil.doExceptionService(e,WithdrawResDTO.class);
        }finally {
            log.info("withdraw 耗时:{} 提现结果:{}",System.currentTimeMillis() - start,result);
            withdrawValidate.release(withdrawDTO,flag);
            MDC.clear();
        }
        return result;
    }


    /**
     * 解冻提现接口
     *
     * @param withdrawDTO               解冻提现请求参数
     * @param traceLogId                日志ID
     * @return                          提现结果
     *                                  response.isSuccess()标示方法的远程调用状态，方法实际执行结果从result 取值
     */
    @Override
    public Result<WithdrawResDTO> unfreezeWithdraw(UnfreezeWithdrawDTO withdrawDTO, String traceLogId) {
        Result<WithdrawResDTO> result = null;
        boolean flag = false;
        try {
            MDC.put(SystemMarker.TRACE_LOG_ID, traceLogId);

            log.info("解冻提现请求参数:withdrawDTO {}", withdrawDTO);
            flag = unfreezeWithdrawValidate.lock(withdrawDTO);

            //1.请求参数校验
            unfreezeWithdrawValidate.paramsValidate(withdrawDTO);
            result = unfreezeWithdrawValidate.validateUniqueOrder(withdrawDTO,withdrawOrderRepository,WithdrawResDTO.class);
            if (result != null) {
                this.existOrderProcess(result);
                return result;
            }
            WithdrawBO withdrawBO = unfreezeWithdrawFactory.build(withdrawDTO);
            withdrawBO.setTradeLogId(traceLogId);

            //3、消费相关信息落地
            withdrawOrderRepository.addUnfreezeWithdrawOrder(withdrawBO);
            //4.业务流程处理
            BackPayBO backPayBO = unfreezeWithdrawHandler.processUnfreeze(withdrawBO);

            //5、接口返回对象生成
            WithdrawResDTO withdrawResDTO = BO2DTOConverter.getWithdrawResDTO(backPayBO);
            result = new Result<>(withdrawResDTO);

        } catch (Exception e) {
            log.error("解冻提现异常:{}", e);
            result = ExceptionUtil.doExceptionService(e, WithdrawResDTO.class);
        } finally {
            log.info("withdraw 解冻提现结果:{}", result);
            unfreezeWithdrawValidate.release(withdrawDTO, flag);
            MDC.clear();
        }
        return result;
    }

    private void existOrderProcess(Result<WithdrawResDTO> result){
        WithdrawResDTO withdrawResDTO = result.getResult();
        withdrawResDTO.setRespDate(new Date());
        withdrawResDTO.setRealRtnFlag(withdrawFactory.getRealRtnFlag(withdrawResDTO.getStatus()));
    }

}
